#include "bsp.h"
#include "mrfi.h"
#include "nwk_types.h"
#include "nwk_api.h"
#include "nwk.h"
#include "bsp_leds.h"
#include "bsp_buttons.h"
#include "CTC.h"
#include "stdlib.h"

static uint8_t RxCallBack(linkID_t);
void CTCinit(void);
void twiddleRCRs(RTS_t**, RCR_t**, uint8_t*, temp_t);
void deleteOldDevices(RTS_t**, RCR_t**);
void deleteOldDevices(RTS_t** RTSarray, RCR_t** RCRarray);

volatile uint8_t numRCRs = 0;
<<<<<<< .mine
volatile uint8_t numRTSs = 0;  //moved initialization inside main for extern
=======
volatile uint8_t numRTSs;  //moved initialization inside main for extern
>>>>>>> .r88

volatile uint8_t RCRsleepTime = DEFAULT_RCR_SLEEP_TIME;
volatile uint8_t RTSsleepTime = DEFAULT_RTS_SLEEP_TIME;
volatile int turnOffBacklightTime;

static linkID_t linkID = 0;
uint8_t receiveBuffer[3] = {0,0,0};
uint8_t length;
volatile uint8_t receivedBroadcast = 0;
volatile uint8_t receivedRequest = 0;
volatile linkID_t receivedLinkID = 0;
volatile int numSeconds = 0;
volatile int turnOffBacklightTime = 0;

unsigned int count = 0;

volatile uint8_t menuLevel;
volatile uint8_t menuControl;
volatile uint8_t menuRow;
volatile uint8_t setTemp = 75;

void main(void)
{	
	RCR_t* RCRs[NUM_RCRS];
	RTS_t* RTSs[NUM_RTSS];
	uint8_t sortedIndices[NUM_RTSS];
	
	RCR_t* RCR;
	RTS_t* RTS;
	
	int nextDecision = DECISION_PERIOD;
	uint8_t i;
	
	CTCinit();
	
	// initialize RCR and RTS arrays
	for(i = 0; i < NUM_RCRS; i++)
		RCRs[i] = NULL;
	for(i = 0; i < NUM_RTSS; i++)
	{
		RTSs[i] = NULL;
		sortedIndices[i] = i;
	}
		
	while(1)
	{
		if(receivedBroadcast)
		{
			// LinkListen will block for ~5 seconds. This should be enough time to wait.
			// We want to only try to link once just in case we get an errant broadcast
			// request from something already linked.
			LCDmoveCursor(3,19);
			LCDprintString("*");
			SMPL_LinkListen(&linkID);
			receivedBroadcast = 0;
		}
		LCDmoveCursor(3,19);
		LCDprintString(" ");
		if(receivedRequest)
		{
			receivedRequest = 0;
		 	if(SMPL_Receive(receivedLinkID, receiveBuffer, &length) != SMPL_SUCCESS)
		 	{
		 		// TODO: handle problem
		 		continue;
		 	}
		 	if(length != 3)
		 	{
		 		// TODO: handle problem
		 		continue;
		 	}
		 	
		 	switch(receiveBuffer[0])
		 	{
		 		// identification frame from an RCR
		 		case RCR_IDENT:
			 		RCR = createNewRCR(receivedLinkID, receiveBuffer[1], RCRsleepTime, receiveBuffer[2]);
				 	addNewRCR(RCRs, RCR);
				 	numRCRs++;
				 	ackRCR(RCRs, receivedLinkID);
				 	BSP_TOGGLE_LED2();
		 			break;
		 		// identification frame from an RTS
		 		case RTS_IDENT:
		 			RTS = createNewRTS(receivedLinkID, receiveBuffer[1], RTSsleepTime, receiveBuffer[2]);
				 	addNewRTS(RTSs, RTS);
				 	if(receiveBuffer[2] == 26)
				 		BSP_TOGGLE_LED1();
				 	numRTSs++;
				 	ackRTS(RTSs, receivedLinkID);
		 			break;
		 		// command request from an RCR
		 		case RCR_REQ:
			 		if(isRCR(RCRs, receivedLinkID))
				 	{
					 	updateRCR(RCRs, receivedLinkID, receiveBuffer[2]);
					 	ackRCR(RCRs, receivedLinkID);
					 	BSP_TOGGLE_LED1();
				 	}
			 		break;
			 	// command request from RTS
		 		case RTS_REQ:
			 		if(isRTS(RTSs, receivedLinkID))
				 	{
				 		// TODO: FIX THIS OFFSET
					 	updateRTS(RTSs, receivedLinkID, receiveBuffer[1], receiveBuffer[2]);
					 		
					 	ackRTS(RTSs, receivedLinkID);
					 	
<<<<<<< .mine
=======
					 	/*
					 	LCDclear();
					 	LCDprintString("RTS temp: ");
					 	LCDprintDecimal(RTSs[0]->temp);
>>>>>>> .r88
					 	*/
					 	if(menuLevel == HOME)
					 	{
					 		printMenu(menuLevel, menuRow, RTSs);
					 	}
					 	
					 	if(menuLevel == HOME)
					 		printMenu(menuLevel, menuRow, RTSs);
					 	
					 	BSP_TOGGLE_LED2();
					 	
					 	/*
					 	 * RTS Data test Code
					 	 * 
					 	RTSIndex = findRTSbyLinkID(RTSs, numRTSs, receivedLinkID);
					 	
					 	if((RTSs[RTSIndex]->temp  == 27) && (RTSs[RTSIndex]->battLife == 50))
					 		BSP_TURN_ON_LED1();
					 	else
					 		BSP_TURN_ON_LED2();
					 	*/
				 	}
			 		break;
		 		default:
		 			break;
		 	}
		 	if(numSeconds >= nextDecision)
		 	{
<<<<<<< .mine
				//deleteOldDevices(RTSs, RCRs);
=======
<<<<<<< .mine
		 		//deleteOldDevices(RTSs, RCRs);
		 		LCDmoveCursor(3,0);
		 		LCDprintString("Errors ");
		 		LCDprintDecimal(sumErrors(RTSs, setTemp));
=======
				deleteOldDevices(RTSs, RCRs);
>>>>>>> .r92
>>>>>>> .r88
		 		if(sumErrors(RTSs, setTemp) >= HVAC_THRESHOLD)
		 		{
		 			twiddleRCRs(RTSs, RCRs, sortedIndices, setTemp);
		 			// turn on the HVAC
		 			P3OUT &= ~(BIT0);
		 		}
		 		else
		 		{
		 			// turn off the HVAC
		 			P3OUT |= BIT0;
		 		}
		 		nextDecision += DECISION_PERIOD;
		 	}
		}
    	if(menuControl)
		{
			menuAction(menuControl, RTSs);
		}
	}
}

void CTCinit(void)
{
	WDTCTL = WDTPW | WDTHOLD;												// Turn off watchdog timer
	BSP_Init();
	SMPL_Init(RxCallBack);													// Start SimpliciTI with the callback function RxCallBack
	
	SMPL_Ioctl(IOCTL_OBJ_RADIO, IOCTL_ACT_RADIO_RXON, 0);		// Enable radio receive
		
	// set up timer to give us a 1 second interrupt
	TA1CCR0 	= ONE_SECOND_PERIOD;		// Load cap comp register with sleep period
	TA1CCTL0 	= CCIE;                     // CCR0 interrupt enabled
	TA1CTL 		= TASSEL_1 + MC_2;          // ACLK, continuous mode
	
	LCDinit();
	menuInit();
	
	setTemp = 75;
	
	// P3.0 is output, controls fans. Initialize it to off.
	P3DIR |= BIT0;
	P3OUT |= BIT0;
	
	LCDclear();
	LCDmoveCursor(0,0);
	LCDprintString("Welcome to");
	LCDmoveCursor(1,0);
	LCDprintString("Distributed HVAC");
	LCDmoveCursor(2,0);
	LCDprintString("Control System");
  
  //Remove the above or insert a delay
  
<<<<<<< .mine
  //printMenu(menuLevel, menuRow, RTSs);
=======
  	//printMenu(menuLevel, menuRow);
>>>>>>> .r88
}

void twiddleRCRs(RTS_t** RTSarray, RCR_t** RCRarray, uint8_t* sortedIndices, temp_t setTemp)
{
	//sortZones(RTSarray, sortedIndices);
	/*
	if(numRTSs/3 == 0)
	{
		openRCR(RCRarray, sortedIndices[0]);
		for(i = 1; i < numRCRs; i++)
		{
			closeRCR(RCRarray, sortedIndices[i]);
		}
	}
	else
	// open the top third of zones
	{
		for(i = 0; i < numRTSs/3; i++)
		{
			openRCR(RCRarray, sortedIndices[i]);
		}
		for(i = numRTSs/3; i < numRTSs; i++)
		{
			closeRCR(RCRarray, sortedIndices[i]);
		}
	}
	*/
<<<<<<< .mine
	// DESIGN DAY "ALGORITHM", V0.1
	if(RTSarray[0] == NULL)
		return;
	if(RTSarray[0] -> temp > setTemp)
		openRCR(RCRarray, RTSarray[0] -> zone);
=======
	
	/* ONE RCR, ONE RTS TEST CODE
	if(RTSarray[sortedIndices[0]] -> temp > 100)
		openRCR(RCRarray, RTSarray[sortedIndices[0]]->zone);
>>>>>>> .r88
	else
		closeRCR(RCRarray, RTSarray[0] -> zone);
	*/
	
<<<<<<< .mine
	if(RTSarray[1] == NULL)
		return;
	if(RTSarray[1] -> temp > setTemp)
		openRCR(RCRarray, RTSarray[1] -> zone);
	else
		closeRCR(RCRarray, RTSarray[1] -> zone);
	
=======
	// DESIGN DAY "ALGORITHM", V0.1
	if(RTSarray[0] == NULL)
		return;
	if(calculateError(RTSarray, 0, setTemp) > 0)
		openRCR(RCRarray, RTSarray[0] -> zone);
	else
		closeRCR(RCRarray, RTSarray[0] -> zone);
	
	if(RTSarray[1] == NULL)
		return;
	if(calculateError(RTSarray, 1, setTemp) > 0)
		openRCR(RCRarray, RTSarray[1] -> zone);
	else
		closeRCR(RCRarray, RTSarray[1] -> zone);
	
>>>>>>> .r88
}

<<<<<<< .mine
void deleteOldDevices(RTS_t** RTSarray, RCR_t** RCRarray)
{
        uint8_t i = 0;
        while(RTSarray[i] != NULL)
        {
                if(RTSarray[i] -> timeLastSeen < (numSeconds - 30))
                {
                        deleteRTS(RTSarray, i);
                        numRTSs--;
                }
                i++;
        }
        i = 0;
        while(RCRarray[i] != NULL)
        {
                if(RCRarray[i] -> timeLastSeen < (numSeconds - 30))
                {
                        deleteRCR(RCRarray, i);
                        numRCRs--;
                }
                i++;
        }
}

=======
void deleteOldDevices(RTS_t** RTSarray, RCR_t** RCRarray)
{
	uint8_t i = 0;
	while(RTSarray[i] != NULL)
	{
		if(RTSarray[i] -> timeLastSeen < (numSeconds - 30))
		{
			deleteRTS(RTSarray, i);
			numRTSs--;
		}
		i++;
	}
	i = 0;
	while(RCRarray[i] != NULL)
	{
		if(RCRarray[i] -> timeLastSeen < (numSeconds - 30))
		{
			deleteRCR(RCRarray, i);
			numRCRs--;
		}
		i++;
	}
}

>>>>>>> .r88
static uint8_t RxCallBack(linkID_t lid)
{
	//BSP_TOGGLE_LED2();
	// Is this a broadcast packet? If so, assume someone is 
	// trying to connect. We don't need to keep the frame.
	if(lid == SMPL_LINKID_USER_UUD)
	{
		receivedBroadcast = 1;
		return DISCARD_FRAME;
	}
	// If it's not a broadcast packet this is from an RCR or RTS.
	// Save the link ID and the frame.
	receivedRequest = 1;
	receivedLinkID = lid;
	return KEEP_FRAME;
}

#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0(void)
{
	TA1CCR0 += ONE_SECOND_PERIOD;	// set new interrupt to occur in 1 second
	
	if(numSeconds++ > turnOffBacklightTime)                 // incrment timer for wait() function
    	P2OUT &= ~BIT7;
	}

<<<<<<< .mine

=======
	if(numSeconds++ > turnOffBacklightTime)			// incrment timer for wait() function
		P2OUT &= ~BIT7;
}


>>>>>>> .r88
